package com.edu.internship.glabal.exception;

import com.edu.internship.glabal.constants.Result;
import com.edu.internship.glabal.constants.ResultCodeEnum;
import com.edu.internship.util.Tools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.net.ConnectException;
import java.sql.SQLException;
import java.util.StringJoiner;

/**
 * code is far away from bug with the animal protecting
 *
 * @author lishiquan
 * @description
 * @date 2022-07-29
 */
@RestControllerAdvice
@Slf4j
public class GlobalDefaultExceptionHandler {

    /**
     * 全局异常 300
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> defaultErrorHandler(Exception ex) {
        log.error("全局异常: [{}]", ex.getMessage(), ex);
        return Result.failure(ResultCodeEnum.INTERNAL_SERVER_ERROR, ex.getMessage());
    }

    /**
     * 业务异常 300
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> businessErrorHandler(BusinessException ex) {
        log.error("业务异常: [{}], msg: [{}]", ex.getMessage(), ex);
        if (Tools.isNotBlank(ex.getMsg())) {
            return Result.failure(ex.getCodeEnum(), ex.getMsg());
        }
        return Result.failure(ex.getCodeEnum(), ex.getCodeEnum().getDesc());
    }

    /**
     * 校验不通过
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<String> validationErrorHandler(MethodArgumentNotValidException ex) {
        StringJoiner sj = new StringJoiner(",");
        ex.getBindingResult().getAllErrors().forEach(error -> sj.add(error.getDefaultMessage()));
        log.error("验证未通过 ==> [{}], 字段 ==> [{}]", ex.getMessage(), sj);
        return Result.failure(ResultCodeEnum.FIELD_VALIDATE_FAILURE, sj.toString());
    }

    /**
     * 缺少请求参数
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> missingServletRequestParameterErrorHandler(MissingServletRequestParameterException ex) {
        log.error("缺少请求参数:[{}]", ex.getMessage());
        return Result.failure(ResultCodeEnum.MISSING_REQUEST_PARAMETER, ex.getMessage());
    }

    /**
     * 请求参数类型错误
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public Result<String> badRequestErrorHandler(BindException ex) {
        log.error("请求参数类型错误:[{}]", ex.getMessage());
        return Result.failure(ResultCodeEnum.BAD_REQUEST, ex.getMessage());
    }

    /**
     * 数据库操作错误1
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = DataAccessException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> databaseErrorHandler(DataAccessException ex) {
        log.error("数据库操作错误1:[{}]", ex.getMessage());
        return Result.failure(ResultCodeEnum.DATABASE_ERROR, ResultCodeEnum.DATABASE_ERROR.getDesc());
    }

    /**
     * 数据库操作错误2
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = SQLException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> databaseErrorHandler(SQLException ex) {
        log.error("数据库操作错误2:[{}]", ex.getMessage());
        return Result.failure(ResultCodeEnum.DATABASE_ERROR, ResultCodeEnum.DATABASE_ERROR.getDesc());
    }

    /**
     * 网络连接失败
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = ConnectException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> connectErrorHandler(ConnectException ex) {
        log.error("网络连接失败:[{}]", ex.getMessage());
        return Result.failure(ResultCodeEnum.CONNECTION_ERROR, ex.getMessage());
    }
}
